home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
Music
/
MIDI
/
smusmidi
/
SMUSMIDI.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-23
|
46KB
|
1,232 lines
/*
** SMUSMIDI.C Copyright © 1991 Thomas E. Janzen
** Converts a DMCS .SMUS file to a standard MIDI file.
** Don't expect it to work on SMUS files from programs other than DMCS.
** 7-7-91 resumed work on it.
** 25 July 91 works pretty well
** 27 July remove double math to avoid linking math lib.
** 15 Aug 91
** 17 August 1991 Works well enough for me. Version 1.0
*/
/* Copyright (c) 1990 by Thomas E. Janzen
All Rights Reserved
THIS SOFTWARE IS FURNISHED FREE OF CHARGE FOR STUDY AND USE AND MAY
BE COPIED ONLY FOR PERSONAL USE OR COMPLETELY AS OFFERED WITH NO
CHANGES FOR FREE DISTRIBUTION. NO TITLE TO AND OWNERSHIP OF THE
SOFTWARE IS HEREBY TRANSFERRED. THOMAS E. JANZEN ASSUMES NO
RESPONSBILITY FOR THE USE OR RELIABILITY OF THIS SOFTWARE.
THOMAS E. JANZEN ASSUMES NO RESPONSIBILITY FOR THE USE OF THIS
SOFTWARE TO COPY MUSICAL SCORE FILES PROTECTED BY COPYRIGHT LAWS.
THIS SOFTWARE IS FOR USE ONLY WITHIN ANY AND ALL APPLICABLE LAWS.
Thomas E. Janzen
58A School St. Apt. 2-L
Hudson, MA 01749
(508)562-1295
*/
/*
** FACILITY:
**
** SMUSMIDI file format convertor on Commodore (TM) Amiga (TM)
** compiled with SAS/C (TM) 5.10a
**
** ABSTRACT:
**
** SMUSMIDI.c converts SMUS files from DMCS (TM Electronic Arts)
** into standard MIDI file format files.
**
** AUTHOR: Thomas E. Janzen
**
** CREATION DATE: 17-AUG-1991
**
** MODIFICATION HISTORY:
** DATE NAME DESCRIPTION
**--
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <proto/exec.h>
#include "iff/iff.h"
#include "iff/smus.h"
#define MIDI_FILE_TYPE ".MID"
#define IDLEN 4
#define TRUE 1
#define FALSE 0
#define SINGLMULTTRAK 0
#define MULTITRACK 1
#define MIDIHDRLEN 14
#define MIDITRKHDRLEN 8
#define SYSEXLEN 4
#define NTRK_POS 12
#define TICKS_PER_QUARTER 240
#define NOTEON 0X90
#define NOTEOFF 0X80
#define META_EVENT 0XFF
#define SEQ_NUM 0X00
#define TEXT_EVENT 0X01
#define COPY_EVENT 0X02
#define TRACK_NAME 0X03
#define INST_NAME 0X04
#define LYRIC_EVENT 0X05
#define MARKER_EVENT 0X06
#define CUE_POINT 0X07
#define CHAN_PREFIX 0X20
#define EOT_EVENT 0X2F
#define TEMPO_EVENT 0X51
#define TIME_SIG_EVENT 0X58
#define KEY_EVENT 0X59
#define MAX_TIES 32
#define MAX_CHORDS 32
#define NOT_OLD_CHORD 0x40000000
struct MIDI_Note_struct {
unsigned char Status_Channel,
Note_Number,
Velocity;
};
typedef struct MIDI_Note_struct MIDI_NOTE_TYPE;
struct MIDI_Header {
unsigned int Chunk_Type;
unsigned int Chunk_Len;
unsigned short int Format;
unsigned short int Num_Tracks;
unsigned short int Division; /* of time, usu. 24 MIDI ticks or SMPTE */
};
typedef struct MIDI_Header MIDI_HEADER_TYPE;
struct MIDI_Track {
unsigned int Chunk_Type;
unsigned int Chunk_Len;
};
typedef struct MIDI_Track MIDI_TRACK_TYPE;
struct Chord_Struct {
unsigned char Pitch,
Tied,
Tied_Back,
Delete;
};
typedef struct Chord_Struct CHORD_TYPE;
static char *MIDItoPitchName (int NoteNum, char *PitchName);
static int SMUS_Len_to_MIDI_Delay (SEvent *Note);
static int Variable_Length_Values (int Number, unsigned char *Array);
static int Search_Tied_Array (char Pitch, char *Tied_Array,
int Tied_Index);
static int Remove_Tied_Note (int Pitch, char *Tied_Array, int Tied_Index);
static void Insert_Null (unsigned int *MIDI_Index,
unsigned char *MIDI_Score);
static void Insert_Meta_Event (unsigned int *MIDI_Index,
unsigned char *MIDI_Score,
unsigned char Event_Type,
unsigned int Event_Len);
static void Send_a_Note ( unsigned int *MIDI_Index,
unsigned char *MIDI_Score,
unsigned char Current_Channel,
unsigned char Current_Dynamic,
unsigned char Pitch,
unsigned char *Running_Status);
static void Shutdown (void);
static int Remove_Chord_Notes ( CHORD_TYPE *Chord_Array,
int Chord_Array_Len);
static int Check_Tie (char *SMUS_Score, int SMUS_Index, SEvent Note,
int FORM_Size);
static int Search_Chord_Array ( char Pitch,
CHORD_TYPE *Chord_Array,
int Chord_Index,
int Tied);
static int Add_Chord_Array (CHORD_TYPE *Chord_Array, unsigned char Pitch,
int Tie, int Tie_Back, int Chord_Index);
static unsigned char *SMUS_Score = NULL,
*MIDI_Score = NULL;
static FILE *SMUS_File = NULL,
*MIDI_File = NULL;
static unsigned int Just_Did_a_Delay = FALSE;
void main (int argc, char *argv[])
{
static unsigned char
Track_String[32],
Current_Channel,
Current_Dynamic = 127,
Tied_Array[MAX_TIES],
key;
static CHORD_TYPE Chord_Array[MAX_CHORDS];
static MIDI_HEADER_TYPE MIDI_FileHdr =
{MakeID('M','T','h','d'), 6,
MULTITRACK, 1, TICKS_PER_QUARTER};
auto MIDI_TRACK_TYPE *MIDI_Track_ptr;
auto unsigned char Score_Name[128],
Running_Status = 0;
static char SMUS_File_Name[128] = "Score.smus",
MIDI_File_Name[128] = "ram:Score",
filemode[2] = "r";
static SScoreHeader Header;
auto unsigned int FORM_Size = 0,
Instrument_Index,
Track,
Temp_ID,
MIDI_Track_Index,
status,
tempint,
ID_int,
MIDI_Delay = 0,
len,
Real_Tie;
#ifdef DEBUG
auto int debug_stopper = 62;
#endif
auto int Chord_Index = 0,
Chord_Counter = 0,
Tied_Index = 0,
Notes_per_Track,
Chord_Note;
static unsigned int Start_of_Tracks_Index,
SMUS_Index = 0,
MIDI_Index = 0,
Caesura = TICKS_PER_QUARTER / 24;
static RefInstrument Instruments[32];
static SEvent Note;
static int Note_Counter;
union {
unsigned int Tempo_int;
unsigned char Tempo_char[4];
} MIDI_Tempo;
if (argc != 3)
{
printf ("usage: SMUSMIDI {SMUS_file} {MIDI_file(no type)}\n");
exit (1);
}
strcpy (SMUS_File_Name, argv[1]);
if ((SMUS_File = fopen (SMUS_File_Name, filemode)) == NULL)
{
printf ("Can't open SMUS input file.\n");
exit (1);
}
strcpy (filemode, "w");
strcpy (MIDI_File_Name, argv[2]);
strcat (MIDI_File_Name, MIDI_FILE_TYPE);
if ((MIDI_File = fopen (MIDI_File_Name, filemode)) == NULL)
{
printf ("Can't open MIDI output file.\n");
Shutdown ();
}
status = fread ((char *)&ID_int, sizeof (int), 1, SMUS_File);
if (ID_int != FORM)
{
printf ("Not a FORM file\n");
Shutdown ();
}
status = fread ((char *)&FORM_Size, sizeof (int), 1, SMUS_File);
printf ("FORM is: %d bytes.\n", FORM_Size);
SMUS_Score = malloc (FORM_Size);
if (SMUS_Score == NULL)
{
printf ("Insufficient memory for SMUS Score\n");
Shutdown ();
exit (0);
}
MIDI_Score = malloc (4 * FORM_Size);
memset (MIDI_Score, '\0', 4 * FORM_Size);
if (MIDI_Score == NULL)
{
printf ("Insufficient memory for MIDI Score\n");
Shutdown ();
}
/* Copy whole file into RAM */
fread (SMUS_Score, FORM_Size, 1, SMUS_File);
fclose (SMUS_File);
SMUS_File = NULL;
/* check for SMUS */
SMUS_Index = 0;
memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], 4);
if (ID_int != ID_SMUS)
{
printf ("Input file was not an SMUS file!?\n");
Shutdown ();
}
SMUS_Index += 4;
/* check for SHDR */
memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], 4);
if (ID_int != ID_SHDR)
{
printf ("No SHDR chunk!\n");
Shutdown ();
}
/* Get the header */
SMUS_Index += 8;
memcpy ((char *)&Header, &SMUS_Score[SMUS_Index],
sizeof (SScoreHeader));
MIDI_FileHdr.Num_Tracks = Header.ctTrack + 1;
/* hope it's < 256 tracks! + tempo track */
printf ("HEADER:\n Tempo: MM %d; %d Tracks\n",
Header.tempo / 128, Header.ctTrack);
SMUS_Index += sizeof (SScoreHeader);
/* Start MIDI_Score */
MIDI_Index = 0;
memcpy (&MIDI_Score[MIDI_Index], &MIDI_FileHdr,
sizeof (MIDI_HEADER_TYPE));
MIDI_Index += sizeof (MIDI_HEADER_TYPE);
/* Check for NAME */
memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
if (ID_int != ID_NAME)
{
printf ("ID Name didn't show up.\n");
Shutdown ();
}
/* Get NAME */
SMUS_Index += IDLEN;
memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
SMUS_Index += sizeof (int);
memcpy ((char *)Score_Name, &SMUS_Score[SMUS_Index], tempint);
Score_Name[tempint] = '\0';
printf ("SCORE: %s\n", Score_Name);
SMUS_Index += tempint + (tempint % 2);
/* Check for INS1 */
do
{
memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
if (ID_int != ID_INS1)
{
printf ("No more instruments.\n");
break;
}
SMUS_Index += IDLEN;
/* copy NAME */
memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
SMUS_Index += sizeof (int);
Instrument_Index = 0;
memcpy ( &Instruments[Instrument_Index],
&SMUS_Score[SMUS_Index], tempint);
Instruments[Instrument_Index].name[tempint - 4] = '\0';
/* terminate name */
printf (" Instrument: %s\n",
Instruments[Instrument_Index].name);
SMUS_Index += tempint + (tempint % 2);
if (Instruments[Instrument_Index].type == INS1_MIDI)
{
printf ("MIDI instrument, channel %d, preset %d\n",
Instruments[Instrument_Index].data1,
Instruments[Instrument_Index].data2);
}
} while (status = TRUE);
/* Instrument index is the number of instruments now.*/
/* I hope all the instruments have been listed by now.*/
/*
** DO THE TEMPO TRACK
*/
Start_of_Tracks_Index = SMUS_Index;
MIDI_Track_ptr = (MIDI_TRACK_TYPE *)(&(MIDI_Score[MIDI_Index]));
MIDI_Track_Index = MIDI_Index;
Temp_ID = MakeID ('M', 'T', 'r', 'k');
memcpy ((char *)&MIDI_Track_ptr->Chunk_Type, (char *)&Temp_ID,
sizeof (int));
MIDI_Index += sizeof (MIDI_TRACK_TYPE);
memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
SMUS_Index += sizeof (int);
memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
SMUS_Index += sizeof (int);
printf ("Length of track: %d bytes\n", tempint);
Notes_per_Track = tempint / sizeof (SEvent);
MIDI_Score[MIDI_Index] = 0; /* must have a delay before an Event */
MIDI_Index++;
MIDI_Score[MIDI_Index] = META_EVENT;
MIDI_Index++;
MIDI_Score[MIDI_Index] = TRACK_NAME;
MIDI_Index++;
len = Variable_Length_Values (5, &MIDI_Score[MIDI_Index]);
MIDI_Index += len;
strcpy (&MIDI_Score[MIDI_Index], "Tempo");
MIDI_Index += 5;
Just_Did_a_Delay = FALSE;
MIDI_Delay = 0;
for (Note_Counter = 0; Note_Counter < Notes_per_Track;
Note_Counter++)
{
memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
SMUS_Index += sizeof (SEvent);
switch (Note.sID)
{
case SID_Rest:
do {
MIDI_Delay += SMUS_Len_to_MIDI_Delay (&Note);
memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
SMUS_Index += sizeof (SEvent);
Note_Counter++;
} while ((Note.sID == SID_Rest)
&& (Note_Counter < Notes_per_Track));
Note_Counter--;
SMUS_Index -= sizeof (SEvent);
Just_Did_a_Delay = TRUE;
break;
case SID_Instrument:
break;
case SID_TimeSig:
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
MIDI_Delay = 0;
Just_Did_a_Delay = TRUE;
Insert_Meta_Event (&MIDI_Index, MIDI_Score, TIME_SIG_EVENT, 4);
MIDI_Score[MIDI_Index] = TimeNSig (Note.data) + 1;
MIDI_Index++;
MIDI_Score[MIDI_Index] = TimeDSig (Note.data);
MIDI_Index++;
MIDI_Score[MIDI_Index] = 24;
MIDI_Index++;
MIDI_Score[MIDI_Index] = 0x08;
MIDI_Index++;
Just_Did_a_Delay = FALSE;
break;
case SID_KeySig:
case SID_Dynamic:
case SID_MIDI_Chnl:
case SID_MIDI_Preset:
case SID_Clef:
break;
case SID_Tempo:
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
MIDI_Delay = 0;
Just_Did_a_Delay = TRUE;
Insert_Meta_Event (&MIDI_Index, MIDI_Score, TEMPO_EVENT, 3);
MIDI_Tempo.Tempo_int = (60 * 1000000) / Note.data;
memcpy (&MIDI_Score[MIDI_Index],
&(MIDI_Tempo.Tempo_char[1]), 3);
MIDI_Index += 3;
break;
case SID_Mark:
break;
default:
if ((SID_FirstNote <= Note.sID) && (Note.sID <= SID_LastNote))
{
if (!IsChord (Note.data)) /* if the note is chorded */
{
MIDI_Delay += SMUS_Len_to_MIDI_Delay (&Note);
}
}
}
}
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
MIDI_Delay = 0;
Just_Did_a_Delay = TRUE;
Insert_Meta_Event (&MIDI_Index, MIDI_Score, EOT_EVENT, 0);
Temp_ID = MIDI_Index - MIDI_Track_Index - 8;
memcpy ((char *)&MIDI_Track_ptr->Chunk_Len, (char *)&Temp_ID,
sizeof (int));
Running_Status = 0;
/*
** end of tempo track
*/
SMUS_Index = Start_of_Tracks_Index;
for (Track = 0; Track < Header.ctTrack; Track++)
{
MIDI_Track_ptr = (MIDI_TRACK_TYPE *)(&(MIDI_Score[MIDI_Index]));
MIDI_Track_Index = MIDI_Index;
Temp_ID = MakeID ('M', 'T', 'r', 'k');
memcpy ((char *)&MIDI_Track_ptr->Chunk_Type, (char *)&Temp_ID,
sizeof (int));
MIDI_Index += sizeof (MIDI_TRACK_TYPE);
/* Make sure you put in the chunk length at the end! */
memcpy ((char *)&ID_int, &SMUS_Score[SMUS_Index], sizeof (int));
if (ID_int != ID_TRAK)
{
printf ("There are no Tracks!\n");
}
SMUS_Index += sizeof (int);
memcpy ((char *)&tempint, &SMUS_Score[SMUS_Index], sizeof (int));
SMUS_Index += sizeof (int);
MIDI_Score[MIDI_Index] = 0; /* must have a delay before an Event */
MIDI_Index++;
MIDI_Score[MIDI_Index] = META_EVENT;
MIDI_Index++;
MIDI_Score[MIDI_Index] = TRACK_NAME;
MIDI_Index++;
sprintf (Track_String, "Track %d", Track);
len = Variable_Length_Values (strlen (Track_String),
&MIDI_Score[MIDI_Index]);
MIDI_Index += len;
strcpy (&MIDI_Score[MIDI_Index], Track_String);
MIDI_Index += strlen (Track_String);
Notes_per_Track = tempint / sizeof (SEvent);
Just_Did_a_Delay = FALSE;
for (Note_Counter = 0; Note_Counter < Notes_per_Track;
Note_Counter++)
{
memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
SMUS_Index += sizeof (SEvent);
switch (Note.sID)
{
case SID_Rest:
MIDI_Delay = 0;
do
{
MIDI_Delay += SMUS_Len_to_MIDI_Delay (&Note);
memcpy (&Note, &SMUS_Score[SMUS_Index], sizeof (SEvent));
SMUS_Index += sizeof (SEvent);
Note_Counter++;
} while ((Note.sID == SID_Rest)
&& (Note_Counter < Notes_per_Track));
Note_Counter--;
SMUS_Index -= sizeof (SEvent);
if (Just_Did_a_Delay) /* 2 delays can't appear together */
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
Just_Did_a_Delay = TRUE;
break;
case SID_Instrument:
case SID_TimeSig:
break;
case SID_KeySig:
switch (Note.data)
{
case 0: case 1: case 2: case 3: case 4: case 5:
case 6: case 7:
key = Note.data & 0x7F;
break;
case 8: case 9: case 10: case 11:
case 12: case 13: case 14:
key = ((7 - Note.data) & 0x7F);
break;
default:
break;
}
Insert_Meta_Event (&MIDI_Index, MIDI_Score, KEY_EVENT, 2);
MIDI_Score[MIDI_Index] = key;
MIDI_Index++;
MIDI_Score[MIDI_Index] = 0x00;
MIDI_Index++;
break;
case SID_Dynamic:
Current_Dynamic = Note.data;
break;
case SID_MIDI_Chnl:
Current_Channel = Note.data;
Insert_Meta_Event (&MIDI_Index, MIDI_Score, CHAN_PREFIX, 1);
MIDI_Score[MIDI_Index] = Note.data;
MIDI_Index++;
break;
case SID_MIDI_Preset:
if (!Just_Did_a_Delay)
{
MIDI_Score[MIDI_Index] = 0;
MIDI_Index++;
}
MIDI_Score[MIDI_Index] = 0xC0 | Current_Channel;
MIDI_Index++;
MIDI_Score[MIDI_Index] = Note.data;
MIDI_Index++;
Running_Status = 0xC0 | Current_Channel;
break;
case SID_Clef:
case SID_Tempo:
case SID_Mark:
break;
default:
if ((SID_FirstNote <= Note.sID) /* if it's a pitch number */
&& (Note.sID <= SID_LastNote))
{
Real_Tie = Check_Tie (SMUS_Score, SMUS_Index,
Note, FORM_Size);
/*
** The following tedious logic decides
** whether to send a note
** whether to delay
** whether to stop the note
** on the basis of
** whether the note is in the tied array
** whether the note is in the chord array
** whether the note is chorded forward
** whether the note is tied forward
*/
#ifdef DEBUG
if (Note.sID == debug_stopper)
{
puts ("stopit");
}
#endif
if (Real_Tie) /* if the note is tied forward */
{
if (Search_Tied_Array (Note.sID, Tied_Array,
Tied_Index)) /* and if the note is tied backward*/
{
if (IsChord (Note.data)) /* and if it's Chorded */
{
if (Search_Chord_Array (Note.sID, Chord_Array,
Chord_Index, Real_Tie) != NOT_OLD_CHORD)
/* and if it's not in an old chord */
{
;
}
else
{
Chord_Index = Add_Chord_Array (Chord_Array,
Note.sID, Real_Tie, TRUE, Chord_Index);
}
}
else /* tied forward and backward,but not chorded*/
/* this means that we are at the end of a chord
** and should play off the non-tied notes in chord
*/
{
if (Search_Chord_Array (Note.sID, Chord_Array,
Chord_Index, Real_Tie) != NOT_OLD_CHORD)
/* tied forward/backward;old chord, not chord */
{
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- Caesura;
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
Just_Did_a_Delay = TRUE;
/* send note off for chord notes */
for ( Chord_Counter = 0;
Chord_Counter < Chord_Index;
Chord_Counter++)
{
if (!Chord_Array[Chord_Counter].Tied)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, 0,
Chord_Array[Chord_Counter].Pitch,
&Running_Status);
Chord_Array[Chord_Counter].Delete
= TRUE;
Tied_Index =
Remove_Tied_Note (
Chord_Array[Chord_Counter].Pitch,
Tied_Array, Tied_Index);
}
}
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Score[MIDI_Index] = Caesura;
MIDI_Index++;
Just_Did_a_Delay = TRUE;
}
else /* tied forward/backward, but
** not in an old chord and not chorded */
{
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- Caesura;
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
Just_Did_a_Delay = TRUE;
/* send note off for non-tied chord notes */
for ( Chord_Counter = 0;
Chord_Counter < Chord_Index;
Chord_Counter++)
{
if (!Chord_Array[Chord_Counter].Tied)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, 0,
Chord_Array[Chord_Counter].Pitch,
&Running_Status);
Chord_Array[Chord_Counter].Delete
= TRUE;
Tied_Index =
Remove_Tied_Note (
Chord_Array[Chord_Counter].Pitch,
Tied_Array, Tied_Index);
}
}
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Score[MIDI_Index] = Caesura;
MIDI_Index++;
Just_Did_a_Delay = TRUE;
}
}
}
else /* tied forward but not backward */
{
/* add to Tied_Array */
Tied_Array[Tied_Index] = Note.sID;
Tied_Index++;
if (IsChord (Note.data)) /*if the note is chorded*/
{
if ((Chord_Note =
Search_Chord_Array (Note.sID, Chord_Array,
Chord_Index, Real_Tie)) == NOT_OLD_CHORD)
/* if not in chord array */
{
Chord_Index = Add_Chord_Array (Chord_Array,
Note.sID, Real_Tie, FALSE, Chord_Index);
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
}
else
{
if (!Chord_Array[Chord_Note].Tied_Back)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
}
}
}
else /* tied forward, not tied back, not chord */
/* we are at the end of a chord, so we have to play
** all the non-tied chord notes */
{
Chord_Note =
Search_Chord_Array (Note.sID, Chord_Array,
Chord_Index, Real_Tie);
if (Chord_Note != NOT_OLD_CHORD)
{
if (!Chord_Array[Chord_Note].Tied_Back)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
}
}
else
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
}
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- Caesura;
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
Just_Did_a_Delay = TRUE;
/* send note off for non-tied chord notes */
for ( Chord_Counter = 0;
Chord_Counter < Chord_Index;
Chord_Counter++)
{
if (!Chord_Array[Chord_Counter].Tied)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, 0,
Chord_Array[Chord_Counter].Pitch,
&Running_Status);
Chord_Array[Chord_Counter].Delete = TRUE;
Tied_Index =
Remove_Tied_Note (
Chord_Array[Chord_Counter].Pitch,
Tied_Array, Tied_Index);
}
}
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Score[MIDI_Index] = Caesura;
MIDI_Index++;
Just_Did_a_Delay = TRUE;
}
}
}
else /* it's not tied to the next note */
{
/* if the note is in the tied array */
if (Search_Tied_Array (Note.sID, Tied_Array,
Tied_Index))
{
Tied_Index =
Remove_Tied_Note (Note.sID, Tied_Array,
Tied_Index);
if (IsChord (Note.data)) /* if chorded */
{
if (Search_Chord_Array (Note.sID, Chord_Array,
Chord_Index, Real_Tie) == NOT_OLD_CHORD)
/* if not in chord array */
{
Chord_Index = Add_Chord_Array (Chord_Array,
Note.sID, Real_Tie, TRUE, Chord_Index);
}
}
else /* tied backward not forward, not a chord */
{
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- Caesura;
/*
** Caesura is for time to get in the note off
** so the synth doesn't choke
*/
MIDI_Index = MIDI_Index + Variable_Length_Values
(MIDI_Delay, &MIDI_Score[MIDI_Index]);
Just_Did_a_Delay = TRUE;
if (Search_Chord_Array (Note.sID, Chord_Array,
Chord_Index, Real_Tie) == NOT_OLD_CHORD)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, 0,
Note.sID, &Running_Status);
}
/* send note off for all chord notes */
for ( Chord_Counter = 0;
Chord_Counter < Chord_Index;
Chord_Counter++)
{
if (!Chord_Array[Chord_Counter].Tied)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, 0,
Chord_Array[Chord_Counter].Pitch,
&Running_Status);
Tied_Index =
Remove_Tied_Note (
Chord_Array[Chord_Counter].Pitch,
Tied_Array, Tied_Index);
Chord_Array[Chord_Counter].Delete = TRUE;
}
}
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Score[MIDI_Index] = Caesura;
MIDI_Index++;
Just_Did_a_Delay = TRUE;
}
}
else /* not tied backwards or forwards */
{
if (IsChord (Note.data)) /* if chorded */
{
if (( Chord_Note = Search_Chord_Array
(Note.sID, Chord_Array, Chord_Index,
Real_Tie)) == NOT_OLD_CHORD)
{
Chord_Index = Add_Chord_Array (Chord_Array,
Note.sID, Real_Tie, FALSE, Chord_Index);
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
/*this was not sending the extra notes*/
}
else
{
if (!Chord_Array[Chord_Note].Tied_Back)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
}
}
}
else /* not tied back or forward, not chorded */
{
Chord_Note =
Search_Chord_Array (Note.sID, Chord_Array,
Chord_Index, Real_Tie);
if (Chord_Note != NOT_OLD_CHORD)
{
if (!Chord_Array[Chord_Note].Tied_Back)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
}
}
else
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, Current_Dynamic,
Note.sID, &Running_Status);
}
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Delay = SMUS_Len_to_MIDI_Delay (&Note)
- Caesura;
MIDI_Index = MIDI_Index
+ Variable_Length_Values
(MIDI_Delay,
&MIDI_Score[MIDI_Index]);
Just_Did_a_Delay = TRUE;
if (Chord_Note == NOT_OLD_CHORD)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, 0,
Note.sID, &Running_Status);
}
/* send note off for all chord notes */
for ( Chord_Counter = 0;
Chord_Counter < Chord_Index;
Chord_Counter++)
{
if (!Chord_Array[Chord_Counter].Tied)
{
Send_a_Note (&MIDI_Index, MIDI_Score,
Current_Channel, 0,
Chord_Array[Chord_Counter].Pitch,
&Running_Status);
Tied_Index =
Remove_Tied_Note (
Chord_Array[Chord_Counter].Pitch,
Tied_Array, Tied_Index);
Chord_Array[Chord_Counter].Delete
= TRUE;
}
}
if (Just_Did_a_Delay)
{
Insert_Null (&MIDI_Index, MIDI_Score);
}
MIDI_Score[MIDI_Index] = Caesura;
MIDI_Index++;
Just_Did_a_Delay = TRUE;
}
}
}
}
Chord_Index = Remove_Chord_Notes (Chord_Array, Chord_Index);
break;
}
}
Insert_Meta_Event (&MIDI_Index, MIDI_Score, EOT_EVENT, 0);
Temp_ID = MIDI_Index - MIDI_Track_Index - 8;
memcpy ((char *)&MIDI_Track_ptr->Chunk_Len, (char *)&Temp_ID,
sizeof (int));
Running_Status = 0;
Chord_Index = 0;
Tied_Index = 0;
}
fwrite (MIDI_Score, MIDI_Index, 1, MIDI_File);
fflush (MIDI_File);
Shutdown ();
exit (0);
}
static int SMUS_Len_to_MIDI_Delay (SEvent *Note)
{
auto long int Length;
Length = (4 * TICKS_PER_QUARTER) << 15; /* one scaled unit is 0x8000 */
if (IsDot (Note->data))
{
Length *= 3;
}
switch (NTuplet (Note->data))
{
case 1: /* triplet */
Length *= 2;
Length /= 3;
break;
case 2: /* quintuplet */
Length *= 4;
Length /= 5;
break;
case 3: /* septuplet */
Length *= 6;
Length /= 7;
break;
default:
break;
}
if (IsDot (Note->data))
{
Length /= 2;
}
Length = Length >> Division (Note->data);
Length += 0x4000; /* add a half unit to round off by truncating. */
Length = Length >> 15;
return Length;
}
static int Variable_Length_Values (int Number, unsigned char *Array)
{
auto unsigned char Byte4,
MSByte,
MIDbyte,
LSByte;
LSByte = (Number & 0x0000007F);
MIDbyte = ((Number & 0x00003F80) >> 7) | 0x80;
MSByte = ((Number & 0x001FC000) >> 14) | 0x80;
Byte4 = ((Number & 0x0FE00000) >> 21) | 0x80;
if (Byte4 != 0x80)
{
Array[0] = Byte4;
Array[1] = MSByte;
Array[2] = MIDbyte;
Array[3] = LSByte;
return 4;
}
if (MSByte != 0x80)
{
Array[0] = MSByte;
Array[1] = MIDbyte;
Array[2] = LSByte;
return 3;
}
if (MIDbyte != 0x80)
{
Array[0] = MIDbyte;
Array[1] = LSByte;
return 2;
}
Array[0] = LSByte;
return 1;
}
static int Search_Tied_Array ( char Pitch,
char *Tied_Array,
int Tied_Index)
{
auto int Tied_Counter;
for (Tied_Counter = 0; Tied_Counter < Tied_Index; Tied_Counter++)
{
if (Pitch == Tied_Array[Tied_Counter])
{
return TRUE;
}
}
return FALSE;
}
static int Search_Chord_Array ( char Pitch,
CHORD_TYPE *Chord_Array,
int Chord_Index,
int Tied)
{
auto int Chord_Counter;
for (Chord_Counter = 0; Chord_Counter < Chord_Index; Chord_Counter++)
{
if (Pitch == Chord_Array[Chord_Counter].Pitch)
{
if (Chord_Array[Chord_Counter].Tied)
{
Chord_Array[Chord_Counter].Tied_Back = TRUE;
}
Chord_Array[Chord_Counter].Tied = Tied;
return Chord_Counter;
}
}
return NOT_OLD_CHORD;
}
static int Remove_Tied_Note (int Pitch, char *Tied_Array, int Tied_Index)
{
auto int Tied_Counter,
Inner_Index;
for (Tied_Counter = 0; Tied_Counter < Tied_Index; Tied_Counter++)
{
if (Tied_Array[Tied_Counter] == Pitch)
{
for ( Inner_Index = Tied_Counter; Inner_Index < Tied_Index;
Inner_Index++)
{
Tied_Array[Inner_Index] = Tied_Array[Inner_Index + 1];
}
Tied_Index--;
break;
}
}
return Tied_Index;
}
static int Remove_Chord_Notes ( CHORD_TYPE *Chord_Array,
int Chord_Array_Len)
{
auto CHORD_TYPE New_Chord_Array[MAX_CHORDS];
auto int Chord_Index = 0,
New_Chord_Counter = 0;
for (Chord_Index = 0; Chord_Index < Chord_Array_Len; Chord_Index++)
{
if (!Chord_Array[Chord_Index].Delete)
{
New_Chord_Array[New_Chord_Counter] = Chord_Array[Chord_Index];
New_Chord_Counter++;
}
}
for (Chord_Index = 0; Chord_Index < New_Chord_Counter; Chord_Index++)
{
Chord_Array[Chord_Index] =New_Chord_Array[Chord_Index];
}
return New_Chord_Counter;
}
static void Insert_Null (unsigned int *MIDI_Index,
unsigned char *MIDI_Score)
{
Insert_Meta_Event (MIDI_Index, MIDI_Score, TEXT_EVENT, 4);
strcpy (&MIDI_Score[*MIDI_Index], "NULL");
(*MIDI_Index) += 4;
return;
}
static void Insert_Meta_Event (unsigned int *MIDI_Index,
unsigned char *MIDI_Score,
unsigned char Event_Type,
unsigned int Event_Len)
{
if (!Just_Did_a_Delay)
{
MIDI_Score[*MIDI_Index] = 0x00;
(*MIDI_Index)++;
}
MIDI_Score[*MIDI_Index] = META_EVENT;
(*MIDI_Index)++;
MIDI_Score[*MIDI_Index] = Event_Type;
(*MIDI_Index)++;
MIDI_Score[*MIDI_Index] = Event_Len;
(*MIDI_Index)++;
Just_Did_a_Delay = FALSE;
return;
}
static void Send_a_Note ( unsigned int *MIDI_Index,
unsigned char *MIDI_Score,
unsigned char Current_Channel,
unsigned char Current_Dynamic,
unsigned char Pitch,
unsigned char *Running_Status)
{
static MIDI_NOTE_TYPE MIDI_Note;
if (!Just_Did_a_Delay)
{
MIDI_Score[*MIDI_Index] = 0x00;
(*MIDI_Index)++;
}
MIDI_Note.Status_Channel = NOTEON | Current_Channel;
MIDI_Note.Note_Number = Pitch;
MIDI_Note.Velocity = Current_Dynamic;
if (MIDI_Note.Status_Channel == *Running_Status)
{
memcpy ( &MIDI_Score[*MIDI_Index], &(MIDI_Note.Note_Number), 2);
(*MIDI_Index) += 2;
}
else /* running status changed */
{
memcpy (&MIDI_Score[*MIDI_Index], &MIDI_Note, sizeof MIDI_Note);
(*MIDI_Index) += sizeof (MIDI_NOTE_TYPE);
*Running_Status = MIDI_Note.Status_Channel;
}
Just_Did_a_Delay = FALSE;
return;
}
static void Shutdown (void)
{
if (SMUS_Score) free (SMUS_Score);
if (MIDI_Score) free (MIDI_Score);
if (SMUS_File) fclose (SMUS_File);
if (MIDI_File) fclose (MIDI_File);
exit (0);
}
static int Check_Tie (char *SMUS_Score, int SMUS_Index, SEvent Note,
int FORM_Size)
{
auto SEvent Note_temp;
/* Pass the end of the current chord to look into the next chord */
if (IsChord (Note.data))
{
do
{
memcpy (&Note_temp, &SMUS_Score[SMUS_Index], sizeof (SEvent));
SMUS_Index += sizeof (SEvent); /* point to next event */
} while ((SMUS_Index < FORM_Size) && (IsChord (Note_temp.data)));
}
/* Now pointing to beginning of next chord or note */
if (!IsTied (Note.data)) /* if it's not tied, it's not tied */
{
return FALSE;
}
/* if it was tied, check that there is a next same pitch to tie to */
while (SMUS_Index < FORM_Size)
{
memcpy (&Note_temp, &SMUS_Score[SMUS_Index], sizeof (SEvent));
SMUS_Index += sizeof (SEvent);
if (( SID_FirstNote <= Note_temp.sID) /* if it's a note event */
&& (Note_temp.sID <= SID_LastNote))
{
if (!IsChord (Note_temp.data)) /* if at end of next chord */
{
if (Note.sID == Note_temp.sID)/*last chance to match tie note*/
{
return TRUE;
}
return FALSE; /* the last note in next chord didn't match */
}
else /* we're in a note inside the next chord */
{
if (Note_temp.sID == Note.sID) /* if it matches the tie */
{
return TRUE; /* return true */
}
} /* otherwise keep looking through this chord */
}
}
return FALSE;
}
static int Add_Chord_Array (CHORD_TYPE *Chord_Array, unsigned char Pitch,
int Tie, int Tie_Back, int Chord_Index)
{
if (Chord_Index == (MAX_CHORDS - 1))
{
puts ("chord array too long");
Shutdown();
}
Chord_Array[Chord_Index].Pitch = Pitch;
Chord_Array[Chord_Index].Tied = Tie;
Chord_Array[Chord_Index].Tied_Back = Tie_Back;
Chord_Array[Chord_Index].Delete = FALSE;
Chord_Index++;
return Chord_Index;
}